Skip to content

fix: minor improvements to event attendance#310

Merged
alexsapps merged 3 commits intomainfrom
alex/event-fixups
Mar 1, 2026
Merged

fix: minor improvements to event attendance#310
alexsapps merged 3 commits intomainfrom
alex/event-fixups

Conversation

@alexsapps
Copy link
Collaborator

@alexsapps alexsapps commented Feb 28, 2026

fixes from #297

Summary by CodeRabbit

  • Documentation

    • Clarified sync timing with a dated reference and tightened notes about activist data handling.
  • Refactor

    • Registry is now initialized separately from storage; storage is provided during an explicit load step.
    • Merge flow simplified to always run merge logic when updates are processed.
  • Bug Fixes

    • Name and ID indexes are consistently rebuilt after merges and removals.
    • Removals use a clearer in-memory update with persistent deletion preserved.

@alexsapps alexsapps requested a review from jakehobbs as a code owner February 28, 2026 23:59
@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72837ff and f89d6ea.

📒 Files selected for processing (1)
  • frontend-v2/src/app/event/activist-registry.ts

📝 Walkthrough

Walkthrough

ActivistRegistry no longer accepts storage in its constructor; storage is provided to loadFromStorage(storage). loadFromStorage rebuilds the in-memory activists list and id/name indexes. mergeActivists now merges in-memory and then rebuilds the name index. removeActivistsByIds now uses an explicit loop to collect remaining activists, updates indexes, and writes deletions through storage when configured.

Changes

Cohort / File(s) Summary
Activist Registry
frontend-v2/src/app/event/activist-registry.ts
Removed storage parameter from constructor(). loadFromStorage(storage: ActivistStorage): Promise<void> now accepts storage and loads activists, rebuilding in-memory list plus id and name indexes. mergeActivists performs merges in-memory and then rebuilds the name index. removeActivistsByIds replaced the filter-based implementation with an explicit loop that collects remaining activists, updates id/name indexes, and performs storage deletions when configured.
Activist Storage
frontend-v2/src/app/event/activist-storage.ts
Documentation timestamp tightened ("as of January 2026"). setLastSyncTime now calls put with { lastSyncTime: timestamp } satisfies SyncMetadata for compile-time type assurance; no runtime behavior changes.
Hook / Wiring
frontend-v2/src/app/event/useActivistRegistry.ts
Instantiate ActivistRegistry() without storage and pass activistStorage into loadFromStorage(activistStorage). Callsite now invokes mergeActivists(activistsToUpdate) unconditionally (removed length check).

Sequence Diagram(s)

sequenceDiagram
    participant Hook as rgba(63,81,181,0.5) Hook (useActivistRegistry)
    participant Registry as rgba(0,150,136,0.5) ActivistRegistry
    participant Storage as rgba(255,87,34,0.5) ActivistStorage

    Hook->>Registry: new ActivistRegistry()
    Hook->>Registry: loadFromStorage(activistStorage)
    Registry->>Storage: readAll()
    Storage-->>Registry: activists[]
    Registry->>Registry: rebuild in-memory list, id & name indexes
    Hook->>Registry: mergeActivists(activistsToUpdate)
    Registry->>Registry: merge in-memory, rebuild name index
    Registry->>Storage: write updates/deletions (if configured)
    Storage-->>Registry: ack
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through code with nimble, careful feet,
Dropped the extra bag, let loader and registry meet,
I stitched names and ids into one tidy nest,
Loops swept out the clutter, indexes put to rest,
A rabbit's tidy merge — simple, swift, and neat.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'fix: minor improvements to event attendance' is vague and does not accurately reflect the specific architectural changes made to the ActivistRegistry, ActivistStorage, and useActivistRegistry modules. Consider a more specific title that describes the main change, such as 'refactor: move storage initialization to loadFromStorage in ActivistRegistry' or 'refactor: defer storage parameter to loadFromStorage method'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch alex/event-fixups

Comment @coderabbitai help to get the list of available commands and usage tips.

@alexsapps alexsapps force-pushed the alex/event-fixups branch from 4ef8b47 to 67a715d Compare March 1, 2026 00:17
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend-v2/src/app/event/activist-registry.ts (1)

18-21: ⚠️ Potential issue | 🟡 Minor

Constructor JSDoc is stale after the signature change.

The comment still documents a storage constructor parameter, but constructor() no longer accepts one. Please update this block to avoid incorrect usage guidance.

📝 Suggested doc fix
 /**
  * In-memory activist registry with write-through storage to IndexedDB.
  *
  * Reads are synchronous (from memory) for fast autocomplete/filtering.
  * Writes are async and automatically persist to IndexedDB when storage is configured.
- *
- * `@param` storage - Optional IndexedDB storage for persistence.
- *                  When provided, enables automatic write-through caching.
- *                  When omitted, registry operates in memory-only mode.
  */
 export class ActivistRegistry {

Also applies to: 28-28

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend-v2/src/app/event/activist-registry.ts` around lines 18 - 21, Update
the stale constructor JSDoc for the ActivistRegistry class: remove or replace
the `@param` storage description since constructor() no longer accepts a storage
parameter, and instead document the current initialization behavior (e.g.,
in-memory-only mode or how persistence is configured elsewhere). Edit the JSDoc
block above the constructor() in activist-registry.ts to reflect the new
signature and initialization semantics so callers aren’t misled by a nonexistent
`storage` parameter.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend-v2/src/app/event/activist-registry.ts`:
- Line 62: mergeActivists currently only replaces existing entries by id, but
the contract requires replacement by id OR by name; update mergeActivists to
treat an incoming activist as a duplicate if either id or name matches an
existing record (use a map keyed by id and a secondary map keyed by normalized
name or check both on lookup), and when a match is found overwrite the existing
entry rather than appending; ensure you update both lookup maps (id and name)
and the resulting activists array so stale same-name/different-id records are
removed/replaced (refer to mergeActivists and the activists accumulation logic
in this file).

---

Outside diff comments:
In `@frontend-v2/src/app/event/activist-registry.ts`:
- Around line 18-21: Update the stale constructor JSDoc for the ActivistRegistry
class: remove or replace the `@param` storage description since constructor() no
longer accepts a storage parameter, and instead document the current
initialization behavior (e.g., in-memory-only mode or how persistence is
configured elsewhere). Edit the JSDoc block above the constructor() in
activist-registry.ts to reflect the new signature and initialization semantics
so callers aren’t misled by a nonexistent `storage` parameter.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ef8b47 and 67a715d.

📒 Files selected for processing (3)
  • frontend-v2/src/app/event/activist-registry.ts
  • frontend-v2/src/app/event/activist-storage.ts
  • frontend-v2/src/app/event/useActivistRegistry.ts


/**
* Merges new activists with existing data, replacing duplicates by id.
* Merges new activists with existing data, replacing duplicates by id and name.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

mergeActivists does not currently replace duplicates by name.

The method contract says replacement happens by id and name, but the implementation only chooses replacement candidates by id. A same-name/different-id incoming record is appended instead of replacing, leaving stale entries and inconsistent semantics.

🔧 Suggested fix for name-based replacement path
 async mergeActivists(newActivists: ActivistRecord[]): Promise<void> {
   if (newActivists.length === 0) {
     return
   }

   const indexById = new Map(this.activists.map((a, i) => [a.id, i]))

   for (const activist of newActivists) {
-    const existingIndex = indexById.get(activist.id) ?? -1
+    const existingByName = this.activistsByName.get(activist.name)
+    const existingIndexById = indexById.get(activist.id) ?? -1
+    const existingIndexByName =
+      existingByName ? (indexById.get(existingByName.id) ?? -1) : -1
+    const existingIndex =
+      existingIndexById >= 0 ? existingIndexById : existingIndexByName

     if (existingIndex >= 0) {
       // Update existing activist (handles renames properly)
       const oldActivist = this.activists[existingIndex]
       this.activists[existingIndex] = activist

       // Remove old name from index if name changed
       if (oldActivist.name !== activist.name) {
         this.activistsByName.delete(oldActivist.name)
       }
+      if (oldActivist.id !== activist.id) {
+        this.activistsById.delete(oldActivist.id)
+        indexById.delete(oldActivist.id)
+      }
+      indexById.set(activist.id, existingIndex)
     } else {
       // Add new activist
       this.activists.push(activist)
       indexById.set(activist.id, this.activists.length - 1)
     }

     // Update indexes
     this.activistsByName.set(activist.name, activist)
     this.activistsById.set(activist.id, activist)
   }

Also applies to: 65-93

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend-v2/src/app/event/activist-registry.ts` at line 62, mergeActivists
currently only replaces existing entries by id, but the contract requires
replacement by id OR by name; update mergeActivists to treat an incoming
activist as a duplicate if either id or name matches an existing record (use a
map keyed by id and a secondary map keyed by normalized name or check both on
lookup), and when a match is found overwrite the existing entry rather than
appending; ensure you update both lookup maps (id and name) and the resulting
activists array so stale same-name/different-id records are removed/replaced
(refer to mergeActivists and the activists accumulation logic in this file).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend-v2/src/app/event/activist-registry.ts (1)

12-32: ⚠️ Potential issue | 🟡 Minor

Stale JSDoc: @param storage no longer applies to constructor.

The @param storage documentation describes a constructor parameter that was removed. Storage is now passed to loadFromStorage() instead. Update the docs to reflect the new API.

📝 Suggested fix
 /**
  * In-memory activist registry with write-through storage to IndexedDB.
  *
  * Reads are synchronous (from memory) for fast autocomplete/filtering.
  * Writes are async and automatically persist to IndexedDB when storage is configured.
- *
- * `@param` storage - Optional IndexedDB storage for persistence.
- *                  When provided, enables automatic write-through caching.
- *                  When omitted, registry operates in memory-only mode.
+ *
+ * Call `loadFromStorage()` after construction to enable IndexedDB persistence.
+ * When storage is not configured, the registry operates in memory-only mode.
  */
 export class ActivistRegistry {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend-v2/src/app/event/activist-registry.ts` around lines 12 - 32, Update
the class JSDoc for ActivistRegistry to remove the outdated "@param storage"
line and replace it with a brief note that persistence is controlled via
loadFromStorage(storage) rather than a constructor parameter; mention that the
registry defaults to in-memory mode and that providing storage to
loadFromStorage enables write-through persistence to IndexedDB, and reference
the loadFromStorage method and the optional storage property in the description
so readers can find the new API.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@frontend-v2/src/app/event/activist-registry.ts`:
- Around line 12-32: Update the class JSDoc for ActivistRegistry to remove the
outdated "@param storage" line and replace it with a brief note that persistence
is controlled via loadFromStorage(storage) rather than a constructor parameter;
mention that the registry defaults to in-memory mode and that providing storage
to loadFromStorage enables write-through persistence to IndexedDB, and reference
the loadFromStorage method and the optional storage property in the description
so readers can find the new API.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67a715d and 72837ff.

📒 Files selected for processing (1)
  • frontend-v2/src/app/event/activist-registry.ts

@alexsapps alexsapps merged commit 812017d into main Mar 1, 2026
2 checks passed
@alexsapps alexsapps deleted the alex/event-fixups branch March 1, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant